package com.lkl.hystrixdemo.order.limitt;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 它是限流算法中最简单最容易的一种算法，比如我们要求某一个接口，1分钟内的请求不能超过10次，我们可以在开始时设置一个计数器，每次请求，该计数器+1；
 * 如果该计数器的值大于10并且与第一次请求的时间间隔在1分钟内，那么说明请求过多，
 * 如果该请求与第一次请求的时间间隔大于1分钟，并且该计数器的值还在限流范围内，那么重置该计数器
 *
 * 注意：如果大量请求在临界的时候，访问，比如在 59秒的时候，访问 10个，在61秒的时候访问10个，相当于在2秒内处理了20个请求。
 * 临界值的问题可以通过滑动计数器的方式解决
 */
public class LimitService {

    private long start = System.currentTimeMillis();

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    private int limitCount = 10; // 最多允许10个线程访问

    private int interval = 60; //间隔时间60秒

    public boolean accquire () {
        long nowTime = System.currentTimeMillis();
        int diff = (int)(nowTime - start) / 1000;
        if (diff > interval) {
            start = nowTime;
            atomicInteger.set(0);
            System.out.println("请求间隔大于10秒，重新计算");
            return true;
        }

        atomicInteger.incrementAndGet();

        if (atomicInteger.get() > limitCount) {
            start = nowTime;
            atomicInteger.set(0);
            System.out.println("10秒内，访问接口次数大于10，请稍后再访问");
            return false;
        }
        System.out.println("正常访问咯");
        return true;
    }

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newCachedThreadPool();
        LimitService limitService = new LimitService();

        for (int i = 0; i < 100; i++) {
            Player player = new Player(limitService);
            executorService.submit(player);
        }

        executorService.shutdown();
    }
}

class Player extends Thread{
    LimitService limitService;

    public Player (LimitService limitService) {
        this.limitService = limitService;
    }
    @Override
    public void run() {
        try {
            if (!limitService.accquire()) {
                System.out.println("你已经被限流了呢");
                return;
            }
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}